#include	"logger.h"
#include	"system.h"

#include	<cstdarg>
#include	<cstdio>
#include	<cstdlib>
#include	<cstring>
#include	<memory>

using namespace std;

static const char LOG_TYPE_DESC[] = "EWIDCCCCCCCCCCCCCCCCCCCCCC";

Logger::Logger()
	: _pFile(nullptr)
	, _pBuf(new char[1024 * 1024])
	, _nLastDay(-1) {}

Logger::~Logger() {
	if (_pFile) fclose(_pFile);
	if (_pBuf) delete[] _pBuf;
}

Logger & Logger::Instance() {
	static unique_ptr<Logger> _iIns;
	if (!_iIns.get()) _iIns.reset(new Logger);
	return *(_iIns.get());
}

void Logger::Log(ELog::Level emLevel, const char * pFmt, ...) {
	std::unique_lock<std::mutex> iAuto(_iLock);
	DateTime iCur;

	if (_nLastDay != iCur.nDay) {
		char pBuf[64] = { 0 };
		snprintf(pBuf, 64, ".supervisor/log/%04d%02d%02d.txt", iCur.nYear, iCur.nMonth, iCur.nDay);
		if ((_pFile = fopen(pBuf, "w")) == NULL) return;
		_nLastDay = iCur.nDay;
	}

	memset(_pBuf, 0, 1024 * 1024);
	int nOffset = snprintf(_pBuf, 1024 * 1024, "[%04d-%02d-%02d %02d:%02d:%02d.%03d][%c] ",
		iCur.nYear, iCur.nMonth, iCur.nDay, iCur.nHour, iCur.nMin, iCur.nSec, iCur.nMSec,
		LOG_TYPE_DESC[emLevel]);

	if (nOffset <= 0) return;

	va_list args;
	va_start(args, pFmt);
	vsnprintf(_pBuf + nOffset, 1024 * 1024 - nOffset, pFmt, args);
	va_end(args);

	fprintf(_pFile, "%s\n", _pBuf);
	fflush(_pFile);

	if (emLevel == ELog::Debug) {
		printf("%s\n", _pBuf);
	} else if (emLevel == ELog::Warning) {
		printf("\033[33m%s\033[0m\n", _pBuf);
	} else if (emLevel == ELog::Error) {
		printf("\033[31m%s\033[0m\n", _pBuf);
	} else {
		printf("\033[32m%s\033[0m\n", _pBuf);
	}
}
